package com.learning.spring.cloud.ms.consumer.movie.controller;

import com.learning.spring.cloud.ms.consumer.movie.entity.User;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

/**
 * ClassName: MovieController
 * Description:
 * Date: 2019/5/31 10:42 【需求编号】
 *
 * @author Sam Sho
 * @version V1.0.0
 */
@Slf4j
@RestController
@RequestMapping("movie")
public class MovieController {

    @Autowired
    private RestTemplate restTemplate;

    /**
     * 添加熔断实现。测试地址：http://localhost:8010/movie/user/1
     * <p>
     * 注意：熔断的状态
     * 1- 当请求失败、被拒绝、超时、断路器打开，都会进入回退。
     * 2- 但是进入回退，不一定在断路器就是打开
     * 3- 断开服务 ms-provider-user ，再从访问测试地址已经进入回退逻辑
     * 4- 然后查看端点 http://localhost:8010/health 可以看到 hystrix 状态还是 up，即断路器没有打开
     * 4- 原因：但是进入回退，不一定在断路器就是打开，需要失败率达到一定的阈值（默认是5s内20次失败）
     *
     * @param id
     * @return
     */
    @GetMapping("/user/{id}")
    @HystrixCommand(fallbackMethod = "findByIdFallback")
    public User findById(@PathVariable Long id) {
        return this.restTemplate.getForObject("http://ms-provider-user/user/" + id, User.class);
    }


    /**
     * 熔断隔离策略与传播上下文
     * <p>
     * hystrix 线程隔离有两种：
     * 1- THREAD（线程隔离）：HystrixCommand 将在单独的线程上执行，并发请求收到线程池中的线程数量的限制。默认推荐这种。
     * 2- SEMAPHORE（信号量隔离）： HystrixCommand 将在调用线程上执行，开销较小，并发请求收到信号量个数的限制
     *
     * @param id
     * @return
     */
    @GetMapping("/user2/{id}")
    @HystrixCommand(fallbackMethod = "findByIdFallback")
    public User findById2(@PathVariable Long id) {
        return this.restTemplate.getForObject("http://ms-provider-user/user/" + id, User.class);
    }


    /**
     * 熔断回调方法：该方法与 findById 方法需要有相同的参数与返回值类型
     *
     * @return
     */
    public User findByIdFallback(Long id, Throwable throwable) {

        log.error("访问回退：", throwable);

        User user = new User();
        user.setId(-1L);
        user.setName("默认用户");
        return user;
    }


}
